package chair;

import java.util.ArrayList;

import chair.Reflex.ReflexType;
import chair.core.Diary;
import chair.core.Stimulus;

/**
 * 
 * Un Organe peut à la fois écouter l'environnement et produire un réflexe.
 * 
 * Si on lui ajoute des fonctions il pourra aussi les verrouiller - callLock() -
 * et effectuer des actions. (NB: comme Thalamus et Striatum sont là l'écoute
 * passive pouvait attendre). Par exemple faire tourner le robot sur lui-même
 * pour regarder s'il est dans un milieu confiné.
 * 
 * NB: organe peut explicitement renvoyer -2 quand il lui est impossible
 * d'effectuer une mesure, mais il est impossible de lui associer réflexe ou
 * stimulus.
 * 
 * TODO: des organes peuvent entrer en compétitions pour des capteurs. Si
 * abaisse tête pour regarder devant il faudra la relever pour laisser intact un
 * éventuel détecteur de pont. Comme un seul Thread s'occupe de tous les organes
 * (Thalamus) il n'y a pas encore de problème pendant que la tête est baissée. À
 * terme : utiliser des files comme avec Function.
 * 
 * @author nomhad
 * 
 */

public abstract class Organ {
	/** Laisse aux héritiers le soin de trouver leurs prénoms */
	private String _name = "Organ";
	/** Cerveau avec lequel est lié */
	private Brain _brain;
	/**
	 * ce que l'organe est actuellement en train de ressentir. Initialisé à -1
	 * pour détecter changement dès première sensation : sense() ne renvoie
	 * jamais cette valeur.
	 */
	private byte _isSensing = -1;
	/**
	 * Ce que l'organe ressentait au tour précédent.
	 */
	private byte _pastSensing = 0;
	/**
	 * Si on l'organe produit un stimulus bref ou bien si il y aura front
	 * descendant Simplification : considère que le front montant par défaut
	 */
	private boolean _spontaneous = true;
	/** Réflexes verrous qu'utilise ce de sens */
	private ArrayList<Reflex> _lockReflexes = new ArrayList<Reflex>();
	/**
	 * Une liste qui va encapsuler chaque valeur que peut retourner l'organe
	 * pour leur associer stimuli et réflexes
	 */
	private ArrayList<Senser> _sensers = new ArrayList<Senser>();
	/**
	 * Un organe en mode passif (_passitivity > 0) ne signale plus ses
	 * changements d'états
	 */
	private int _passivity = 0;
	/** Sauvegarde du sens actif lors du passage à l'état passif */
	private byte _lastActiveSensing = 0;

	/** réflexes à associer pour toutes les Senseurs créés à la volée */
	private ArrayList<Reflex> _defaultReflexes;

	/**
	 * Chaque occurrence de cette classe représente une sensation que peut
	 * produire un organe.
	 * 
	 * Valeur réservée : 0 pour absence de signal
	 * 
	 * Valeur réservée : -1 en interne, car pour Thalamus cela revient à ignorer
	 * organe (TODO: cette limitation est bancale).
	 * 
	 * Valeur réservée : -2 si ne peut pas répondre. Pour ce dernier cas,
	 * revient à passer son tour, pour contexte, réflexe, etc. À noter cependant
	 * qu'un contexte peut être généré avec ce -2, par exemple si un autre
	 * organe signale un changement. Ça reste une "sensation" comme une autre.
	 * 
	 * NB: le fait de pouvoir à la fois référencer une sensation par sa valeur
	 * et par son nom n'est pas vraiment économe en code mais permet plus de
	 * flexibilité depuis l'extérieur.
	 * 
	 * @author nomhad
	 * 
	 */
	private class Senser {
		/** valeur associée à ce senseur */
		byte value;
		/**
		 * Afin d'être plus explicite : possible de lui donner un nom. Par
		 * défaut sera une simple chaîne de caractère contenant la valeur
		 */
		String name;
		/** Stimuli associés */
		Stimulus stim;
		/**
		 * si l'organe est actuellement en train de prédire le stimulus de ce
		 * sens
		 */
		boolean isPredicting = false;
		/**
		 * Type de réflexe reliés à cette valeur de sens. 0: aucun, 1: réflexes
		 * physiologiques, 2: réponses prédictibles
		 */
		private int linkedRefType = 0;
		/** Réflexes reliés à cette valeur de sens */
		private ArrayList<Reflex> linkedReflexes = new ArrayList<Reflex>();

		Senser(byte val) {
			value = val;
			name = "" + val;
		}

		/**
		 * Relie le présent senseur aux réflexes physiologiques
		 * 
		 * @param res
		 */
		void plugToReflex(Reflex res) {
			synchronized (linkedReflexes) {
				// On est pas très tolérent si on veut brancher des choses
				// identiques
				if (linkedReflexes.contains(res))
					throw new IllegalArgumentException(
							"Réflexe déjà ajouté auparavant à ce sens");
				linkedReflexes.add(res);
			}
			// MAJ plus grand type associé
			if (res.getType() == ReflexType.RESPONSE)
				linkedRefType = 2;
			// Seulement si une précédente réponse ne l'a pas fixé à 2
			else if (res.getType() == ReflexType.REFLEX && linkedRefType != 2)
				linkedRefType = 1;
		}

		/**
		 * Va entraîner les actions sur toutes les réflexes associées si elles
		 * existent. Ce qui tient un peu lieu de listener ici. Actions pas
		 * ordonnées directement mais via Striatum (gère aussi comportements)
		 * 
		 * @param toggle
		 *            allumer ou éteindre réflexe
		 */
		void callReflexe(boolean toggle) {
			synchronized (linkedReflexes) {
				for (Reflex res : linkedReflexes)
					// On ne cherche pas à verrouiller les fonctions
					if (res.getType() != ReflexType.LOCK)
						// Un réflexe avec timer n'a pas besoin de front
						// descendant
						if (!res.hasTimer() || toggle)
							_brain.getStriatum().addReflexe(res,
									new Impulse(toggle, value, name));
			}
		}

		/**
		 * Par rapport à callReflexe ici c'est à un ensemble plus restreint de
		 * réflexes qu'on à affaire, ceux pouvant résulter d'un aprentissage.
		 * Ceux provoqués par tick() lors de la prédiction du modèle.
		 * 
		 * TODO: pas de liste séparrée de _linkedReflexes car de déclenchement
		 * pourrait devenir compliqué. Voir si impact vraiment trop
		 * performances.
		 * 
		 * @param toggle
		 *            allumer ou éteindre réponse
		 */
		void callResponse(boolean toggle) {
			synchronized (linkedReflexes) {
				for (Reflex res : linkedReflexes)
					if (res.getType() == ReflexType.RESPONSE)
						// Un réflexe avec timer n'a pas besoin de front
						// descendant
						if (!res.hasTimer() || toggle)
							_brain.getStriatum().addResponse(res,
									new Impulse(toggle, value, name));
			}
		}

		@Override
		public boolean equals(Object obj) {
			if (obj instanceof Senser) {
				Senser other = (Senser) obj;
				return value == other.value;
			}
			return false;
		}
	}

	public Organ(Brain brain) {
		_brain = brain;
		// La valeur 0 signifie absence de sensation, on la crée dès le début
		synchronized (_sensers) {
			_sensers.add(new Senser((byte) 0));
		}
		// S'enregistre auprès du cerveau
		_brain.addOrgan(this);
	}

	/**
	 * Peut donner explicitement un nom à l'organe lors construction
	 * 
	 * @param brain
	 *            cerveau correspondant
	 * @param name
	 *            nom de l'ogane
	 */
	public Organ(Brain brain, String name) {
		this(brain);
		_name = name;
	}

	/**
	 * Permet de forcer depuis l'extérieur le type de spontanéité de l'organe
	 * 
	 * TODO: peut-être pas souhaitable de pouvoir changer physiologie de
	 * l'organe à la volée
	 * 
	 * @param isSpontaneous
	 *            true si stimulus spontanné, false si aura un début puis une
	 *            fin (persistance dans le temps)
	 */
	final protected void setSpontaneous(boolean isSpontaneous) {
		_spontaneous = isSpontaneous;
	}

	/**
	 * Permet d'ajouter le même stimulus à toutes les valeurs définies pour
	 * l'organe. À manier avec précaution si on définit des Reflex.RESPONSE
	 * (chevauchement à étudier). Utiliser impérativement avant
	 * setStimulus(Stimulus, int) si on veut associer des stimuli précis à
	 * quelques valeurs particulières. 0 n'est pas compris dans le lot, utiliser
	 * setStimulus(Stimulus, byte) pour lui associer explicitement un stimulus.
	 * 
	 * @param stim
	 *            Un Organe produira un certain stimulus
	 */
	final protected void setStimulus(Stimulus stim) {
		synchronized (_sensers) {
			synchronized (_sensers) {
				// Ce cas n'arrive normalement jamais : 0 ajouté dans
				// construction. Plus que normalement donc.
				if (_sensers.size() == 0)
					throw new IllegalArgumentException(
							"Impossile d'ajouter stimulus : aucune valeur définie pour ce sens");
				else
					for (Senser sens : _sensers) {
						if (sens.value != 0)
							sens.stim = stim;
						// Un seule valeur et c'est 0 : on ajoute rien et on le
						// fait bien savoir
						else if (_sensers.size() == 1) {
							throw new IllegalArgumentException(
									"Impossile d'ajouter stimulus : aucune valeur autre que 0 définie pour ce sens");
						}
					}
			}
		}
		_brain.plugStimulus(stim);
	}

	/**
	 * Cette méthode permet de définir un stimulus particulier pour une certaine
	 * valeur retournée par l'organe.
	 * 
	 * @param stim
	 *            Un Organe produira un certain stimulus
	 * @param value
	 *            À quelle valeur est associée ce stimulus
	 */
	final protected void setStimulus(Stimulus stim, byte value) {
		Senser sens = selectSenser(value);
		sens.stim = stim;
		_brain.plugStimulus(stim);
	}

	/**
	 * Il est parfois plus parlant depuis l'extérieur de relier un stimulus au
	 * nom d'une sensation plutôt qu'à sa valeur.
	 * 
	 * @param stim
	 *            Un Organe produira un certain stimulus
	 * @param name
	 *            À quelle sensation est associée ce stimulus
	 */
	final protected void setStimulus(Stimulus stim, String name) {
		Senser sens = selectSenser(name);
		sens.stim = stim;
		_brain.plugStimulus(stim);
	}

	/**
	 * Retourne l'object Senser encapsulant cette valeur. Lève exception si ne
	 * trouve aucune correspondance.
	 * 
	 * @param value
	 *            valeur recherchée
	 * @return Senser de _sensers
	 */
	private Senser selectSenser(byte value) {
		synchronized (_sensers) {
			// Dans implémentation il y a parcours, m'évite d'utiliser quelques
			// octets à encapsuler value pour utiliser méthodes de ArrayList
			for (Senser sens : _sensers)
				if (sens.value == value)
					return sens;
		}
		throw new IllegalArgumentException(
				"Aucun senseur enregistré avec valeur : " + value);
	}

	/**
	 * Retourne l'object Senser encapsulant ce nom. Lève exception si ne trouve
	 * aucune correspondance.
	 * 
	 * @param name
	 *            nom recherché
	 * @return Senser de _sensers
	 */
	private Senser selectSenser(String name) {
		synchronized (_sensers) {
			for (Senser sens : _sensers)
				if (sens.name == name)
					return sens;
		}
		throw new IllegalArgumentException(
				"Aucun senseur enregistré avec ce nom");
	}

	/**
	 * Relie toutes les valeurs mesurées d'un organe aux réflexes
	 * physiologiques. Attention, étudier les recouvrements
	 * d'extinction/stimulation pour des Reflex.RESPONSE et des stimulus
	 * identiques.
	 * 
	 * 0 n'est pas branché au réflexe (absence de donnée). Utiliser
	 * plugToReflex(Reflex, byte) pour explicitement l'y associer.
	 * 
	 * @param res
	 *            réflexe à ajouter
	 */
	final void plugToReflex(Reflex res) {
		synchronized (_sensers) {
			// Ce cas n'arrive normalement jamais : 0 ajouté dans
			// construction. Plus que normalement donc.
			if (_sensers.size() == 0)
				throw new IllegalArgumentException(
						"Impossible d'ajouter réflexe : aucune valeur définie pour ce sens");
			else
				for (Senser sens : _sensers) {
					if (sens.value != 0)
						sens.plugToReflex(res);
					// Un seule valeur et c'est 0 : on ajoute rien et on le
					// fait bien savoir
					else if (_sensers.size() == 1) {
						throw new IllegalArgumentException(
								"Impossile d'ajouter réflexe : aucune valeur autre que 0 définie pour ce sens");
					}
				}
		}
	}

	/**
	 * Relie une valeur mesurée aux réflexes physiologiques.
	 * 
	 * @param res
	 *            réflexe à ajouter
	 * @param value
	 *            valeur associée
	 */
	final void plugToReflex(Reflex res, byte value) {
		selectSenser(value).plugToReflex(res);
	}

	/**
	 * Tous les nouveaux senseurs ajoutés après cette méthode contiendront les
	 * réflexes en question.
	 * 
	 * @param res
	 *            réflexe à ajouter automatiquement à toute nouvelle valeur
	 *            mesurée par l'organe
	 */
	final void plugToDefaultReflex(Reflex res) {
		if (_defaultReflexes == null)
			_defaultReflexes = new ArrayList<Reflex>();
		synchronized (_defaultReflexes) {
			_defaultReflexes.add(res);
		}
	}

	/**
	 * Retourne un entier représentant ce qu'il distingue dans son
	 * environnement.
	 * 
	 * Note :valeurs de retour discrétisées intentionnellement : c'est à
	 * l'organe d'effectuer les étapes de pré-traitement permettant de donner
	 * une certaine signification à ce qu'il mesure. Codé sur byte et non int
	 * car on a tous besoin d'un peu de discrimination.
	 * 
	 * @return -2 si ne peut rien mesurer (à utiliser avec parcimonie si on veut
	 *         utiliser le contexte), 0 si ne mesure rien, sinon la valeur
	 * 
	 */
	protected abstract byte sense();

	/**
	 * Organe envoie influx vers modèle pour connaître activation et autre
	 * influx pour activer réflexe. Appelé par Thalamus, qui n'utilise que si
	 * hasChanged() == true
	 * 
	 * TODO: remonter gestion modèle vers Thalamus tout comme Striatum s'en
	 * charge et non Behavior ?
	 * 
	 */
	final synchronized void fire() {
		Diary.logln(this + "Fire" + _isSensing + " !");

		// On éteint le précédent réflexe (-2: peu pas déssider, -1: utilisé
		// pour signaler dans organe contexte non pertinent, mais ici aussi pour
		// premier passage
		if (_pastSensing != -2 && _pastSensing != -1)
			selectSenser(_pastSensing).callReflexe(false);
		// Active les nouveaux réflexes
		selectSenser(_isSensing).callReflexe(true);

		// Si organe spontané alors on n'envoie pas le front descendant du
		// précédent stimulus au modèle
		if (!_spontaneous && _pastSensing != -2 && _pastSensing != -1) {
			Stimulus prevStim = selectSenser(_pastSensing).stim;
			if (prevStim != null)
				_brain.handleEvent(prevStim, false);
		}
		// Si existe envoie front montant
		Stimulus stim = selectSenser(_isSensing).stim;
		if (stim != null)
			_brain.handleEvent(stim, true);
	}

	/**
	 * Utilise sense() pour mettre à jour état, si détecte changement renvoie
	 * true
	 */
	final boolean hasChanged() {
		_pastSensing = _isSensing;
		_isSensing = sense();
		// Tout l'intérêt du mode passif est de mesurer sans signaler
		// changements à Thalamus. De façon analogue -2 permet de se faire tout
		// petit quand on sèche.
		if (isPassive() || _isSensing == -2)
			return false;
		if (_isSensing != _pastSensing)
			// Changement entre état précédent et actuel
			return true;
		return false;
	}

	/**
	 * Utilisé par Thalamus.checkContext pour savoir comment caractériser
	 * l'environnememnt ; mais tout le monde peut aussi vouloir l'info.
	 * 
	 * @return ce que l'organe mesure actuellement
	 */
	final public byte getSensing() {
		return _isSensing;
	}

	/**
	 * Permet de mettre un nom sur la sensation mesurée par l'Organe. Attention
	 * : à manier avec précaution (cad: pas à une fréquence élevée) car l'appel
	 * est bien plus coûteux que celui de son cousin ne reposant que sur byte.
	 * 
	 * @return nom correspondant à la sensation actuelle
	 */
	final public String getSensingName() {
		return selectSenser(_isSensing).name;
	}

	/**
	 * On fait tourner l'organe pour prédiction.
	 * 
	 * TODO: mettre écoute du modèle ailleurs ?
	 */
	final void tick() {
		// Si une des valeurs de l'organe entraîne des réflexes prédictibles :
		// interroge modèle -> bottom-up
		synchronized (_sensers) {
			if (_sensers.size() > 0) {
				for (Senser sens : _sensers) {
					if (sens.stim != null && sens.linkedRefType == 2) {
						if (_brain.checkForecast(sens.stim)) {
							if (!sens.isPredicting) {
								Diary.logln(this + "Nouvelle prédiction"
										+ sens.stim);
								// La prédiction est nouvelle : on active le
								// réflexe
								sens.callResponse(true);
								sens.isPredicting = true;
							}
						} else if (sens.isPredicting) {
							Diary.logln(this + "Plus prédiction" + sens.stim);
							// Prédiction vient de s'arrêter : on éteint le
							// réflexe
							sens.callResponse(false);
							sens.isPredicting = false;
						}
					}
				}
			}
		}
	}

	/**
	 * Si l'organe n'est pas seulement sensitif mais doit aussi manipuler
	 * certaines fonction il faudra qu'il les vérouille. Pour cela on ajoute des
	 * réflexes de type LOCK aux fonctions. Aucune action ne leur est associée
	 * si ce n'est laisser le champ libre à l'organe. Lève une exception si on
	 * tente de lui ajouter deux fois la même fonction (il y aurait blocage du
	 * fait que deux lock ne peuvent pas se faire en même temps).
	 * 
	 * @param fct
	 *            Function que va utiliser l'organe
	 */
	final protected void addFunction(Function fct) {
		// On parcours la liste des réflexes pour vérifier qu'un jumeau existe
		// pas déjà
		synchronized (_lockReflexes) {
			for (Reflex ref : _lockReflexes)
				if (ref.getType() == ReflexType.LOCK
						&& ref.getFunction() == fct)
					throw new IllegalArgumentException(
							"Fonction déjà ajoutée auparavant à cet organe");
			_lockReflexes.add(new ReflexLock(fct, _name));
		}
	}

	/**
	 * Un organ cherche à obtenir le contrôle de la ou les fonctions qui lui on
	 * été associées.
	 * 
	 * Je pourrais tenir une liste séparée des réflexes de type LOCK...ou bien
	 * la parcourir et n'envoyer au striatum que ce dont j'ai besoin
	 */
	final protected void callLock() {
		synchronized (_lockReflexes) {
			for (Reflex res : _lockReflexes)
				if (res.getType() == ReflexType.LOCK)
					_brain.getStriatum().addReflexe(res, new Impulse(true));
		}
	}

	/**
	 * L'organe décide qu'il n'a plus besoin de monopoliser des fonctions,
	 * dévérouille chacun des réflexes associés.
	 */
	final protected void releaseLock() {
		synchronized (_lockReflexes) {
			for (Reflex res : _lockReflexes)
				if (res.getType() == ReflexType.LOCK)
					res.releaseLock();
		}
	}

	/**
	 * L'organe a auparavant demandé à vérouiller les fonctions associées et
	 * s'informer du processus n'est que légitime de sa part.
	 * 
	 * @return true si toutes les fonctions sont prêtes à être utilisées, false
	 *         sinon
	 */
	final protected boolean hasLock() {
		synchronized (_lockReflexes) {
			for (Reflex res : _lockReflexes)
				if (res.getType() == ReflexType.LOCK)
					if (!res.isLocked())
						return false;
		}
		return true;
	}

	/**
	 * Un organe se déclare comme neutre si à aucune de ses valeurs n'est
	 * associée un stimulus impliquant une récompense ou une punition. Utilisé
	 * par Thalamus afin de savoir quels organes sont pertinent pour définir le
	 * contexte.
	 * 
	 * @return true si cet organe n'influe pas sur le "mental" du robot.
	 */
	final boolean isNeutral() {
		// TODO: condition : type == US et/ou reward == 0 ?
		// TODO: un petit désagrément peut très bien être le contexte d'une
		// grosse récompense
		synchronized (_sensers) {
			for (Senser sens : _sensers)
				if (sens.stim != null && sens.stim.getReward() != 0)
					return false;
		}
		return true;
	}

	/**
	 * Si un organe veut servir il faut qu'il retourne des valeurs, et il faut
	 * impérativement que lors de sa construction il signale celles qu'il va
	 * produire. Ceci afin de pouvoir leur associer par la suite des stimuli et
	 * des réflexes. Possible de les déclarer en plusieurs fois du moment qu'il
	 * n'y a pas répétition. 0 est réservé : signifie que l'organe ne mesure
	 * rien. -1 est de même réservé : signifie qu'on ne peut rien mesurer
	 * (organe "passe son tour").
	 * 
	 * Ajoute les réflexes par défaut s'ils ont été définis.
	 */
	final protected void registerValues(byte[] values) {
		synchronized (_sensers) {
			for (int i = 0; i < values.length; i++) {
				switch (values[i]) {
				case 0:
					throw new IllegalArgumentException(
							"0 est une valeur réservée impossible à ajouter à cet organe (signifie que ne mesrure rien)");
				case -1:
					throw new IllegalArgumentException(
							"-1 est une valeur réservée en interne impossible à ajouter à cet organe");
				case -2:
					throw new IllegalArgumentException(
							"-2 est une valeur réservée en interne impossible à ajouter à cet organe (signifie que ne peut rien mesurer)");
				default:
					Senser sens = new Senser(values[i]);
					if (_sensers.contains(sens))
						throw new IllegalArgumentException(
								"Valeur déjà ajoutée auparavant à cet organe");
					else {
						_sensers.add(sens);
						if (_defaultReflexes != null)
							synchronized (_defaultReflexes) {
								for (Reflex ref : _defaultReflexes)
									sens.plugToReflex(ref);
							}
					}
					break;
				}
			}
		}
	}

	/**
	 * Identique à registerValues(byte[] values) mais permet en plus de nommer
	 * les sensations. À chaque case du tableau values le nom associé sera celui
	 * de la case correspondante dans le tableau names. Ils doivent avoir la
	 * même taille.
	 * 
	 * @param values
	 *            tableau des nouvelles valeurs codans les sensations de
	 *            l'organe
	 * @param names
	 *            tableau des nom correspondants
	 */
	final protected void registerValues(byte[] values, String[] names) {
		// C'est tout ou rien
		if (values.length != names.length)
			throw new IllegalArgumentException(
					"Il n'y a pas le même nombre de valeurs et de noms");
		// On enregistre les valeurs de manière classique puis on les nomme un
		// par un
		registerValues(values);
		for (int i = 0; i < values.length; i++) {
			Senser sense = selectSenser(values[i]);
			sense.name = names[i];
		}

	}

	/**
	 * Lors de situations particulières on peut avoir besoin que l'ogane
	 * effectue de nouvelles mesures sans que celles-ci déclenchent des
	 * réflexes. Par exemple explorer un tracé. Ne pas se contenter d'un
	 * booléens permet à plusieurs entités de demander passivité sans
	 * interférences. En interne un compteur gère les demandes multiples de
	 * passivité.
	 * 
	 * La dernière mesure de l'état actif est enregistré pour la rétablir quand
	 * l'ogane quitte l'état passif.
	 * 
	 * NB: à distinguer du renvoie de la valeur "-2", qui elle signifie
	 * qu'aucune mesure n'est possible. Ici, même en étant passif l'organe
	 * effectue bien une mesure...qui pourquoi pas peut-être "-2", mais évitons
	 * de couper les cheveux en quatre.
	 * 
	 * @param toggle
	 *            true pour désactiver réflexes, false pour revenir à l'état
	 *            normal
	 */
	synchronized public void setPassive(boolean toggle) {
		if (toggle)
			_passivity++;
		else
			_passivity--;
		// On ne peut pas rendre un organe moins passif que ça
		if (_passivity < 0)
			throw new IllegalArgumentException("Cet organe n'est pas passif.");
		else if (_passivity == 0) {
			Diary.logln(this + " revient à ses activités normales.");
			_isSensing = _lastActiveSensing;
		} else if (_passivity > 0) {
			Diary.logln(this + " prend du repos.");
			_lastActiveSensing = _isSensing;
		}
	}

	/**
	 * Est-ce que l'organe doit actuellement masquer ses changements à Thalamus
	 * ?
	 * 
	 * @return true le cas échéant
	 */
	protected boolean isPassive() {
		return _passivity > 0;
	}

	@Override
	public String toString() {
		return "Organ [_name=" + _name + "]";
	}
}
